#pragma once
#include <string>
#include <sstream>
#include <vector>	//split string.
#include <map>
#include <curl/curl.h>
#include <base64.h>

#include "mymutex.hxx"

//404 Page Not Found, just refresh/reload it.
//503 too busy server.
#define CAN_RE_REQUEST(retcode)	(retcode == CURLE_GOT_NOTHING \
				|| retcode == CURLE_COULDNT_CONNECT\
				|| retcode == CURLE_SEND_ERROR\
				|| retcode == CURLE_OPERATION_TIMEDOUT\
				|| retcode == 404)

namespace Utility
{
	CURL* NewCURL(void);
	void CleanupCurl(CURL* curl);

	std::string EscapeStr(std::string str);

	std::string ConvertUTF8toGB2312(const char *unistring, int len);
	string ConvertUTF8toGB2312(const string& data);
	std::string ConvertGB2312toUTF8(const char *pData, size_t size);
	std::string ConvertGB2312toUTF8(const std::string& s);
	
	int PerformStep(CURL* curl, const std::string& url, const std::string& dataFields, stringstream& bodystream);
	bool FileContain(const std::stringstream& bodystream, const string& str, int tellg = 0);
	bool FileContainAny(const std::stringstream& bodystream, const std::vector<std::string>& strs, int tellg = 0);
	string ExtractField(const std::stringstream& bodystream, const string& start, const string& end, int tellg = 0);
	string ExtractAttr(const std::stringstream& bodystream, const string& containing, const string& attrName, int tellg = 0);
	bool ExtractFields(const std::stringstream& bodystream, const string& start, const string& end, std::vector<std::string>& fields, int tellg = 0);
	bool ExtractSelectOptions(const std::stringstream& bodystream, const string& start, std::map<std::string, std::string>& options, string& selected=string(), int tellg = 0);

	bool ExtractTable(const std::stringstream& bodystream, const string& tableName, std::vector<std::string>& items);

	int Encode(const std::string& in, std::string& out);
	int Decode(const std::string& in, std::string& out);
	std::string GetCTime(void);
	std::string GetAnotherDate(std::string today, int distance=7);
	std::string DateToDay(std::string day);
	time_t GetNextWorkDay(void);
	time_t GetNextWorkDay(time_t clock);
	std::string GetDayAsString(time_t clock);

	std::vector<std::string> &split(const std::string &s, char delim, std::vector<std::string> &elems);
	std::vector<std::string> split(const std::string &s, char delim);

	std::string replace(std::string& str, char c, char replacement);
	std::string spaceStr(int length);

	std::string RandFloat16(void);

	class Lock
	{
	public:
	Utility::Lock(Mutex* mutex1) : mutex(mutex1)
		{
			mutex->Lock();
		}
		~Lock()
		{
			mutex->Unlock();
		}

	private:
		Mutex* mutex;
	};
}